/// Checks whether a string is null, empty, or contains only whitespace.
///
/// Returns `true` if the string is:
/// - `null`
/// - Empty string (`''`)
/// - Contains only whitespace characters after trimming
extension NullableStringUtils on String? {
  bool get isNullOrEmpty => this == null || this!.trim().isEmpty;
  bool get isNotNullOrEmpty => !isNullOrEmpty;
}

extension NullableStringValidators on String? {
  bool get isValidPositiveNumber =>
      this != null && RegExp(r'^\+?[0-9]+$').hasMatch(this!);

  bool get isNotValidPositiveNumber => !isValidPositiveNumber;

  bool get isValidNumber =>
      this != null && RegExp(r'^[-+]?\d+(\.{1}\d+)?$').hasMatch(this!);

  bool get isNotValidNumber => !isValidNumber;
}

/// Formats a Chinese mobile phone number with separators.
///
/// Example: `13917042193` → `139-1704-2193`
///
/// [phoneNumber] should be an 11-digit Chinese mobile number starting with 1.
/// [separator] defines the character used between number segments (default: '-')
///
/// Returns the original input if it doesn't match expected phone number format.
extension PhoneNumberFormatting on String {
  String formatMobilePhoneNumber({String separator = '-'}) {
    // Remove any existing formatting
    final cleaned = replaceAll(RegExp(r'[^\d]'), '');

    if (cleaned.length == 11) {
      return '${cleaned.substring(0, 3)}$separator'
          '${cleaned.substring(3, 7)}$separator'
          '${cleaned.substring(7)}';
    }

    return this;
  }
}

extension StringSearch on String? {
  /// Returns the position of all the matches of [pattern] in this string,
  List<int> allIndexesOf(String pattern) {
    if (isNullOrEmpty) {
      return [];
    }

    // All the matched indexes.
    final indexes = <int>[];

    if (pattern.isNotNullOrEmpty) {
      // Starting search at [start]. Default is the beginning.
      var start = 0;

      // Finds the first match.
      var index = this!.indexOf(pattern);

      // Tryies to find next one if matches.
      while (index > -1) {
        // Adds match to return result.
        indexes.add(index);

        // Calculates next start based on current index..
        start = index + pattern.length;

        // If start still within whole length then we can search next match.
        // Otherwise search is complete.
        if (start < this!.length) {
          index = this!.indexOf(pattern, start);
        } else {
          break;
        }
      }
    }

    return indexes;
  }
}
